/**
 * created by 小卷毛, 2019-09-18 018
 * Copyright (c) 2019, 416143467@qq.com All Rights Reserved.
 * #                   *********                            #
 * #                  ************                          #
 * #                  *************                         #
 * #                 **  ***********                        #
 * #                ***  ****** *****                       #
 * #                *** *******   ****                      #
 * #               ***  ********** ****                     #
 * #              ****  *********** ****                    #
 * #            *****   ***********  *****                  #
 * #           ******   *** ********   *****                #
 * #           *****   ***   ********   ******              #
 * #          ******   ***  ***********   ******            #
 * #         ******   **** **************  ******           #
 * #        *******  ********************* *******          #
 * #        *******  ******************************         #
 * #       *******  ****** ***************** *******        #
 * #       *******  ****** ****** *********   ******        #
 * #       *******    **  ******   ******     ******        #
 * #       *******        ******    *****     *****         #
 * #        ******        *****     *****     ****          #
 * #         *****        ****      *****     ***           #
 * #          *****       ***        ***      *             #
 * #            **       ****        ****                   #
 */
package com.zhiyou.aifeng.common_ui.utils

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.lzy.okgo.exception.HttpException
import com.lzy.okgo.exception.StorageException
import com.uber.autodispose.AutoDispose.autoDisposable
import com.uber.autodispose.CompletableSubscribeProxy
import com.uber.autodispose.FlowableSubscribeProxy
import com.uber.autodispose.SingleSubscribeProxy
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
import com.zhiyou.aifeng.common.event.BaseViewEvent
import com.zhiyou.aifeng.common.helper.optNotEmpty
import io.reactivex.*
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.subscribeBy
import io.reactivex.schedulers.Schedulers
import org.json.JSONObject
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.TimeUnit

/**
 * 切换线程 Single
 */
fun <T> applySchedulers() =
    SingleTransformer<T, T> {
        it.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
    }

/**
 * 切换线程 Observable
 */
fun <T> applyObservableSchedulers() =
    ObservableTransformer<T, T> {
        it.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
    }

/**
 * 切换线程 Flowable
 */
fun <T> applyFlowableSchedulers() =
    FlowableTransformer<T, T> {
        it.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
    }

/**
 * 切换线程 Completable
 */
fun applyCompletableSchedulers() =
    CompletableTransformer {
        it.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
    }

/**
 * 切换线程 Single
 */
fun <T : Any> Single<T>.toMain(withDelay: Long = 0): Single<T> =
    this.subscribeOn(Schedulers.io())
        .delay(withDelay, TimeUnit.MILLISECONDS)
        .observeOn(AndroidSchedulers.mainThread())

/**
 * 切换线程 Observable
 */
fun <T : Any> Observable<T>.toMain(withDelay: Long = 0): Observable<T> =
    this.subscribeOn(Schedulers.io())
        .delay(withDelay, TimeUnit.MILLISECONDS)
        .observeOn(AndroidSchedulers.mainThread())

/**
 * 切换线程 Flowable
 */
fun <T : Any> Flowable<T>.toMain(withDelay: Long = 0): Flowable<T> =
    this.subscribeOn(Schedulers.io())
        .delay(withDelay, TimeUnit.MILLISECONDS)
        .observeOn(AndroidSchedulers.mainThread())

/**
 * 绑定生命周期 Single
 */
fun <T : Any> Single<T>.bindLifeCycle(owner: LifecycleOwner): SingleSubscribeProxy<T> =
    this.`as`(
        autoDisposable(
            AndroidLifecycleScopeProvider.from(
                owner,
                Lifecycle.Event.ON_DESTROY
            )
        )
    )

/**
 * 绑定生命周期 Flowable
 */
fun <T : Any> Flowable<T>.bindLifeCycle(owner: LifecycleOwner): FlowableSubscribeProxy<T> =
    this.`as`(
        autoDisposable(
            AndroidLifecycleScopeProvider.from(
                owner,
                Lifecycle.Event.ON_DESTROY
            )
        )
    )

/**
 * 绑定生命周期 Completable
 */
fun Completable.bindLifeCycle(owner: LifecycleOwner): CompletableSubscribeProxy =
    this.`as`(
        autoDisposable<Any>(
            AndroidLifecycleScopeProvider.from(
                owner,
                Lifecycle.Event.ON_DESTROY
            )
        )
    )

/**
 * 订阅发布 Single
 */
fun <T : Any> SingleSubscribeProxy<T>.subscribeBy(
    onSuccess: (T) -> Unit = {},
    onError: (Throwable) -> Unit = {}
): Disposable = subscribe(onSuccess, onError)

/**
 * 订阅发布 Flowable
 */
fun <T : Any> FlowableSubscribeProxy<T>.subscribeBy(
    onNext: (T) -> Unit = {},
    onComplete: () -> Unit = {},
    onError: (Throwable) -> Unit = {}
): Disposable = subscribe(onNext, onError, onComplete)

/**
 * 订阅发布 Single
 * 对返回String数据异常的处理封装
 */
fun <T : Any> Single<T>.subscribeByNoError(
    event: BaseViewEvent? = null,
    toast: Boolean = true,
    onSuccess: (T) -> Unit = {},
    onError: (Throwable) -> Unit = {}
): Disposable = subscribeBy(
    onSuccess = {
        if (it is String && event != null) {
            val json = JSONObject(it)
            val msgCode = json.optString("ret", "")

            if (msgCode == "1") {
                @Suppress("UNCHECKED_CAST")
                onSuccess(json.optNotEmpty("data", "{}") as T)
            } else {
                val msg = json.optNotEmpty("msg", "网络数据请求失败，请联系管理员！")
                if (toast) event.showToast(msg)
            }
        } else {
            onSuccess(it)
        }
    },
    onError = {
        when (it) {
            is UnknownHostException -> event?.showToast("网络连接失败，请连接网络！")
            is ConnectException -> event?.showToast("网络连接失败，请连接网络！")
            is SocketTimeoutException -> event?.showToast("网络请求超时！")
            is HttpException -> event?.showToast("服务器发生未知错误！")
            is StorageException -> event?.showToast("SD卡不存在或没有权限！")
            else -> event?.showToast("网络数据请求失败！")
        }

        onError(it)
    }
)

/**
 * 订阅发布 Single
 * 对返回String数据异常的处理封装
 */
fun <T : Any> SingleSubscribeProxy<T>.subscribeByNoCheck(
    event: BaseViewEvent? = null,
    onSuccess: (T) -> Unit = {},
    onError: (Throwable) -> Unit = {},
    onFinally: () -> Unit = {}
): Disposable = subscribeBy(
    onSuccess = {
        if (it is String && event != null) {
            onSuccess(it)
            onFinally()
        } else {
            onSuccess(it)
            onFinally()
        }
    },
    onError = {
        when (it) {
            is UnknownHostException -> event?.showToast("网络连接失败，请连接网络！")
            is ConnectException -> event?.showToast("网络连接失败，请连接网络！")
            is SocketTimeoutException -> event?.showToast("网络请求超时！")
            is HttpException -> event?.showToast("服务器发生未知错误！")
            is StorageException -> event?.showToast("SD卡不存在或没有权限！")
            else -> event?.showToast("网络数据请求失败！")
        }

        onError(it)
        onFinally()
    }
)

/**
 * 订阅发布 Single
 * 对返回String数据异常的处理封装
 */
fun <T : Any> SingleSubscribeProxy<T>.subscribeByNoError(
    event: BaseViewEvent? = null,
    toast: Boolean = true,
    onSuccess: (T) -> Unit = {},
    onError: (Throwable) -> Unit = {},
    onFinally: () -> Unit = {}
): Disposable = subscribeBy(
    onSuccess = {
        if (it is String && event != null) {
            val json = JSONObject(it)
            val msgCode = json.optString("ret", "")

            if (msgCode == "1") {
                @Suppress("UNCHECKED_CAST")
                onSuccess(json.optNotEmpty("data", "{}") as T)
            } else {
                val msg = json.optNotEmpty("msg", "网络数据请求失败，请联系管理员！")
                if (toast) event.showToast(msg)
            }
            onFinally()
        } else {
            onSuccess(it)
            onFinally()
        }
    },
    onError = {
        when (it) {
            is UnknownHostException -> event?.showToast("网络连接失败，请连接网络！")
            is ConnectException -> event?.showToast("网络连接失败，请连接网络！")
            is SocketTimeoutException -> event?.showToast("网络请求超时！")
            is HttpException -> event?.showToast("服务器发生未知错误！")
            is StorageException -> event?.showToast("SD卡不存在或没有权限！")
            else -> event?.showToast("网络数据请求失败！")
        }

        onError(it)
        onFinally()
    }
)

/**
 * 订阅发布 Single
 * 对返回String数据和状态码异常的处理封装
 */
fun <T : Any> SingleSubscribeProxy<T>.subscribeByNoErrorWithException(
    event: BaseViewEvent? = null,
    toast: Boolean = true,
    onSuccess: (T) -> Unit = {},
    onError: (Throwable) -> Unit = {},
    onException: (String) -> Unit = {},
    onFinally: () -> Unit = {}
): Disposable = subscribeBy(
    onSuccess = {
        if (it is String && event != null) {
            val json = JSONObject(it)
            val msgCode = json.optString("ret", "")

            if (msgCode == "1") {
                @Suppress("UNCHECKED_CAST")
                onSuccess(json.optNotEmpty("data", "{}") as T)
            } else {
                val msg = json.optNotEmpty("msg", "网络数据请求失败，请联系管理员！")
                if (msgCode == "11") onException(msgCode)
                else {
                    if (toast) event.showToast(msg)
                }
            }
            onFinally()
        } else {
            onSuccess(it)
            onFinally()
        }
    },
    onError = {
        when (it) {
            is UnknownHostException -> event?.showToast("网络连接失败，请连接网络！")
            is ConnectException -> event?.showToast("网络连接失败，请连接网络！")
            is SocketTimeoutException -> event?.showToast("网络请求超时！")
            is HttpException -> event?.showToast("服务器发生未知错误！")
            is StorageException -> event?.showToast("SD卡不存在或没有权限！")
            else -> event?.showToast("网络数据请求失败！")
        }

        onError(it)
        onFinally()
    }
)

/**
 * 订阅发布 Flowable
 * 对列表数据异常的处理封装
 */
fun <T : Any> Flowable<T>.subscribeByFinally(
    event: BaseViewEvent? = null,
    onSuccess: (T) -> Unit = {},
    onFinally: () -> Unit = {},
    onError: (Throwable) -> Unit = {}
): Disposable = subscribeBy(
    onNext = { onSuccess(it) },
    onComplete = { onFinally() },
    onError = {
        when (it) {
            is UnknownHostException -> event?.showToast("网络连接失败，请连接网络！")
            is ConnectException -> event?.showToast("网络连接失败，请连接网络！")
            is SocketTimeoutException -> event?.showToast("网络请求超时！")
            is HttpException -> event?.showToast("服务器发生未知错误！")
            is StorageException -> event?.showToast("SD卡不存在或没有权限！")
            else -> event?.showToast("网络数据请求失败！")
        }

        onError(it)
        onFinally()
    }
)

/**
 * 订阅发布 Flowable
 * 对列表数据异常的处理封装
 */
fun <T : Any> FlowableSubscribeProxy<T>.subscribeByFinally(
    event: BaseViewEvent? = null,
    onSuccess: (T) -> Unit = {},
    onFinally: () -> Unit = {},
    onError: (Throwable) -> Unit = {}
): Disposable = subscribeBy(
    onNext = { onSuccess(it) },
    onComplete = { onFinally() },
    onError = {
        when (it) {
            is UnknownHostException -> event?.showToast("网络连接失败，请连接网络！")
            is ConnectException -> event?.showToast("网络连接失败，请连接网络！")
            is SocketTimeoutException -> event?.showToast("网络请求超时！")
            is HttpException -> event?.showToast("服务器发生未知错误！")
            is StorageException -> event?.showToast("SD卡不存在或没有权限！")
            else -> event?.showToast("网络数据请求失败！")
        }

        onError(it)
        onFinally()
    }
)